#include <stdlib.h>
#include <iostream>
#include <glib.h>
#include <string.h>
#include <pbc.h>
#include "celia.h"
#include "common.h"
#include <stdio.h>
#include "policy_lang.h"
#include "plaintext_map.h"

using namespace std;
char **atts = 0;
char **encAtts = 0;
element_t h;

gint str_cmp(gconstpointer a, gconstpointer b){
	return strcmp((const char*)a,(const char*)b);
}

//to generate the hash map i -> g^i
void setup(kpabe_pub_t* pub){
	plaintext_map_initialize(100,pub->p);
}

void parseAttributeUniverse(){
	GSList* alist;
	GSList* ap;
	alist = 0;
	ap = 0;
	char** tmp = (char**)malloc(2*sizeof(char*));
	tmp[0] = "x";
	tmp[1] = "y";
	int n=2;
	for (int i=0; i<n; i++)
		parse_attribute_universe(&alist,tmp[i]);
	alist = g_slist_sort(alist,str_cmp);
	n = g_slist_length(alist);
	atts = (char**)malloc((n+1)*sizeof(char*));
	int i=0;
	for (ap = alist; ap; ap = ap->next)
		atts[i++] = (char*)ap->data;
	cout << " ************* i = " << i << " vs n = "<<n << endl;

	atts[i] = 0;
}

void parseEncryptionAttributes(){
	GSList* alist;
	GSList* ap;
	alist = 0;
	ap = 0;
	char** tmp = (char**)malloc(2*sizeof(char*));
	tmp[0] = "x";
	int n=1;
	for (int i=0; i<n; i++)
		parse_attribute(&alist,tmp[i]);
	alist = g_slist_sort(alist,str_cmp);
	n = g_slist_length(alist);
	encAtts = (char**)malloc((n+1)*sizeof(char*));
	int i=0;
	for (ap = alist; ap; ap = ap->next)
		encAtts[i++] = (char*)ap->data;
	cout << " ************* i = " << i << " vs n = "<<n << endl;
	encAtts[i] = 0;

}

int main(int argc, char** argv){
	cout << "Hello world" << endl;
	
	kpabe_pub_t* pub;
	kpabe_msk_t* msk;
	
	parseAttributeUniverse();
	parseEncryptionAttributes();

	kpabe_setup(&pub, &msk, atts);
	element_init_GT(h,pub->p);
	element_random(h);

	setup(pub);

	element_t zu, v,hashVal, mask;
	element_init_Zr(zu,pub->p);
	element_init_Zr(v,pub->p);
	element_init_Zr(mask,pub->p); //masking the sum
	
	element_random(mask);
	element_random(zu);
	element_div(v,msk->y,zu);
	element_printf("g = %B\n Y = %B\n s = %B\n zu = %B\n s/zu = %B\n",pub->g, pub->Y,
msk->y, zu, v);	
	
	char plaintext[] = "10";
	cout << "size of plaintext = " << sizeof(plaintext)/sizeof(char) << endl;	
	
	toElement(hashVal,27, mask, pub->p);	
	element_printf("hashVal = %B, length = %d\n",hashVal, element_length_in_bytes(hashVal));
	cout << "begin to encrypt " << endl;

	kpabe_cph_t *cph = kpabe_enc_raw(pub,hashVal,encAtts);
	
	GByteArray* buf = kpabe_cph_serialize(cph);
	element_printf(" E = %B\n",cph->Ep);
	cout << "ciphertext length = "<< buf->len << " " << buf->len << endl;
	FILE* f;
	f = fopen("output","w");
	fwrite(buf->data,1,buf->len,f);
	fclose(f);


	char *cond = "x or y";
	char* policy = parse_policy_lang(cond);
	kpabe_prv_t* prv = kpabe_keygen_proxy(pub,msk,policy, zu);
	
	element_t decVal;
	element_t userCiphertext;
	int s = kpabe_transform(pub,prv,cph,userCiphertext);	
	cout << "Decrypt successful = " << s << endl; 
	kpabe_dec_proxy(pub,userCiphertext,zu,cph,decVal);
	element_printf("decVal = %B\n",decVal);

	//unsigned char* dat = (unsigned char*) malloc(element_length_in_bytes(decVal));
	//element_to_bytes(dat,decVal);
	////cout << "data = " << dat << endl;

	cout << "plaintex = " << toPlaintext(decVal,mask, pub->p) << endl;
	cout << "comapre element = " << element_cmp(hashVal,decVal) << endl;
	return 0;
}
